﻿using Newtonsoft.Json;
using SocketIOClient;
using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using System.Windows.Forms;
using System.Drawing;
using System.Windows.Input;
using System.Net.WebSockets;
using System.Net.Sockets;
using System.Net;

namespace ChatRoom
{
    public enum AppStatus
    {
        Init,
        Connected,
        Disconnected,
    }

    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow
    {

        private delegate void AddMessageDelegate(AppMessage msg);

        private MessageWindow mw;

        private NotifyIcon _notifyIcon = null;
        private AppStatus status;
        private SocketIO client;
        public MainWindow()
        {
            InitializeComponent();
            InitialTray();
            printTipInfo();
            InitialMessageWindow();
            this.status = AppStatus.Init;
        }

        #region Init

        /// <summary>
        /// 设置托盘的各个属性
        /// </summary>
        private void InitialTray()
        {
            _notifyIcon = new NotifyIcon();
            _notifyIcon.Text = MessageGetter.start;
            _notifyIcon.Visible = true;//托盘按钮是否可见
            _notifyIcon.Icon = new Icon(@"image.ico");//托盘中显示的图标
            _notifyIcon.BalloonTipText = MessageGetter.hide;
            _notifyIcon.ShowBalloonTip(2000);//托盘气泡显示时间
            _notifyIcon.BalloonTipText = MessageGetter.pop;
            _notifyIcon.MouseClick += notifyIcon_MouseLeftClick;
            _notifyIcon.MouseClick += notifyIcon_MouseRightClick;
            this.StateChanged += MainWindow_StateChanged;
        }

        /// <summary>
        /// 打印提示信息
        /// </summary>
        private void printTipInfo()
        {
            this.InfoTB.Text += MessageGetter.line;
            this.InfoTB.Text += MessageGetter.wpfversion + MessageGetter.newline;
            this.InfoTB.Text += MessageGetter.apiversion + MessageGetter.newline;
            this.InfoTB.Text += MessageGetter.line;
            this.InfoTB.Text += MessageGetter.tiplogin + MessageGetter.newline;
            this.InfoTB.Text += MessageGetter.line;
            this.URLTB.Text = MessageGetter.defaulturl;
        }

        /// <summary>
        /// 初始化弹幕窗口
        /// </summary>
        private void InitialMessageWindow()
        {
            // init
            mw = new MessageWindow();
            // set screen position
            double ScreenHeight = System.Windows.SystemParameters.PrimaryScreenHeight;
            double ScreenWidth = System.Windows.SystemParameters.PrimaryScreenWidth;
            this.mw.Left = ScreenWidth - this.mw.Width;
            this.mw.Top = System.Windows.SystemParameters.WorkArea.Bottom - this.mw.Height;
            // display waring tip
            AddMessage(new AppMessage("warning", "要是多连了就会收到重复消息！", AppStatus.Init));
            // set window always top most
            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Tick += always_Topmost_Ticker;
            timer.Start();
        }

        /// <summary>
        /// 用于使弹幕窗口总保持置顶
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void always_Topmost_Ticker(object sender, EventArgs e)
        {
            this.mw.Topmost = true;
        }

        #endregion

        #region Events

        /// <summary>
        /// 弹幕开关按钮点击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OpenCloseButton_Click(object sender, RoutedEventArgs e)
        {
            // switch message window show/hide
            if (this.mw.IsVisible)
            {
                mw.Hide();
                this.OpenCloseButton.Header = "开启";
            }
            else
            {
                mw.Show();
                this.OpenCloseButton.Header = "关闭";
            }

        }

        /// <summary>
        /// 连接按钮点击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ConnectButton_Click(object sender, RoutedEventArgs e)
        {
            if (this.status != AppStatus.Connected)
                Connect();
            else
                Disconnect();
        }

        /// <summary>
        /// 托盘鼠标右击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void notifyIcon_MouseRightClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                if (this.mw.IsVisible) this.mw.Hide();
                else this.mw.Show();
            }
        }

        /// <summary>
        /// 托盘鼠标左击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void notifyIcon_MouseLeftClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (this.Visibility == Visibility.Visible)
                {
                    _notifyIcon.ShowBalloonTip(500);
                    this.Visibility = Visibility.Hidden;
                }
                else
                {
                    this.Visibility = Visibility.Visible;
                    this.Activate();
                }
            }
        }

        /// <summary>
        /// 窗口状态改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainWindow_StateChanged(object sender, EventArgs e)
        {
            // if minimized then show tip and hide main window
            if (this.WindowState == WindowState.Minimized)
            {
                _notifyIcon.ShowBalloonTip(500);
                this.Visibility = Visibility.Hidden;
                this.WindowState = WindowState.Normal;
            }
        }

        /// <summary>
        /// 窗口关闭
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            this.mw.Close();
        }

        #endregion

        #region Helper

        /// <summary>
        /// 向弹幕添加消息，更新状态
        /// </summary>
        /// <param name="msg"></param>
        void AddMessage(AppMessage msg)
        {
            // to log console
            this.InfoTB.Text += MessageGetter.newline;
            this.InfoTB.Text += msg.user + ":  " + msg.message;
            // to message window
            this.mw.InfoTB.Text += MessageGetter.newline;
            this.mw.InfoTB.Text += msg.user + ":  " + msg.message;
            // update scroller position
            this.InfoSV.ScrollToVerticalOffset(this.InfoSV.ScrollableHeight + this.InfoSV.ViewportHeight);
            this.mw.InfoSV.ScrollToVerticalOffset(this.mw.InfoSV.ScrollableHeight + this.mw.InfoSV.ViewportHeight);
            // update app status
            this.status = msg.status;
            if (this.status == AppStatus.Connected)
            {
                this.ConnectButton.Header = "断开";
                this.URLTB.IsEnabled = false;
            }
            else
            {
                this.ConnectButton.Header = "连接";
                this.URLTB.IsEnabled = true;
            }
        }

        /// <summary>
        /// 更新UI
        /// </summary>
        /// <param name="msg">消息对象</param>
        void UIHandler(AppMessage msg)
        {
            this.InfoTB.Dispatcher.Invoke(new AddMessageDelegate(AddMessage), msg);
        }

        /// <summary>
        /// 解析消息
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        AppMessage Json2Class(String json)
        {
            Message m = JsonConvert.DeserializeObject<Message>(json);
            return new AppMessage(m, AppStatus.Connected);
        }

        #endregion

        #region Logic
        /// <summary>
        /// 断开连接
        /// </summary>
        private void Disconnect()
        {
            try
            {
                // 开启SocketIO任务
                client.CloseAsync().Wait();
            }
            catch (AggregateException ae)
            {
                ae.Handle((x) =>
                {
                    return HandleException(x);
                });
            }
            catch (Exception e)
            {
                AddMessage(new AppMessage("unknown error", e.Message, AppStatus.Disconnected));
            }
        }

        /// <summary>
        /// 连接
        /// </summary>
        private void Connect()
        {
            string url = URLTB.Text;
            try
            {
                // 开启SocketIO任务
                ConnectSIO(url).Wait();
            }
            catch (AggregateException ae)
            {
                ae.Handle((x) =>
                {
                    return HandleException(x);
                });
            }
            catch (Exception e)
            {
                AddMessage(new AppMessage("unknown error", e.Message, AppStatus.Disconnected));
            }
        }

        /// <summary>
        /// 错误处理
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        private bool HandleException(Exception e)
        {
            if (e is AggregateException)
            {
                ((AggregateException)e).Handle((x) =>
                {
                    return HandleException(x);
                });
                return true;
            }
            else if (e is SocketException)
            {
                AddMessage(new AppMessage("error", e.Message, AppStatus.Disconnected));
                return true;
            }
            else if (e is WebSocketException)
            {
                AddMessage(new AppMessage("error", e.Message, AppStatus.Disconnected));
                return true;
            }
            else if (e is WebException)
            {
                AddMessage(new AppMessage("error", e.Message, AppStatus.Disconnected));
                return true;
            }
            else return false;
        }

        /// <summary>
        /// Socket.io任务
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        async Task ConnectSIO(String url)
        {
            client = new SocketIO(url);

            client.On("chatmessage", args => UIHandler(Json2Class((String)args.Text)));

            client.OnConnected += async () =>
            {
                //await Task.Delay(3000);
                await client.EmitAsync("username", "拼房舍友的弹幕姬，划掉，掉幕姬");
            };

            client.OnClosed += (ServerCloseReason reason) =>
            {
                switch (reason)
                {
                    case ServerCloseReason.Aborted:
                        UIHandler(new AppMessage("info", "连接已断开 : Aborted", AppStatus.Disconnected));
                        break;
                    case ServerCloseReason.ClosedByClient:
                        UIHandler(new AppMessage("info", "连接已断开 by client", AppStatus.Disconnected));
                        break;
                    case ServerCloseReason.ClosedByServer:
                        UIHandler(new AppMessage("info", "连接已断开 by server", AppStatus.Disconnected));
                        break;
                }
            };

            await client.ConnectAsync();
        }

        #endregion

    }
}